package com.gitee.dolt.utils.bank;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpStatus;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONException;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.script.JavaScriptEngine;
import cn.hutool.script.ScriptUtil;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
import lombok.extern.slf4j.Slf4j;

import javax.script.ScriptException;


/**
 * 银行卡工具
 *
 * @author LYH
 */
@Slf4j
public class BankCardUtils {

    private static final int MIN_LENGTH = 15;
    private static final int MAX_LENGTH = 19;
    private static JavaScriptEngine javaScriptEngine;

    static {
        javaScriptEngine = ScriptUtil.getJavaScriptEngine();
        String s = IoUtil.read(BankCardUtils.class.getClassLoader()
                .getResourceAsStream("bankCardInfo.js"), CharsetUtil.UTF_8);
        try {
            javaScriptEngine.eval(s);
        } catch (Exception e) {

        }
    }

    /**
     * 获取银行卡信息
     *
     * @param cardNo 银行卡号
     * @return
     * @throws BankCardInfoException
     */
    public static BankCardInfo getBankCardInfo(String cardNo) throws BankCardInfoException {
        if (StrUtil.isEmpty(cardNo) || cardNo.length() < MIN_LENGTH || cardNo.length() > MAX_LENGTH) {
            throw new BankCardInfoException(StrUtil.format("银行卡位数必须是{}到{}位", MIN_LENGTH, MAX_LENGTH));
        }
        if (!NumberUtil.isNumber(cardNo)) {
            throw new BankCardInfoException("银行卡号必须是数字");
        }
        ScriptObjectMirror result = (ScriptObjectMirror) invokeFunction("getBankInfoByCardNo", cardNo);
//        result = null;
        String bankCode;
        String bankName;
        String cardType;
        String cardTypeName;
        if (result == null) {
            String url = StrUtil.format("https://ccdcapi.alipay.com/validateAndCacheCardInfo.json?_input_charset=utf-8&cardNo={}&cardBinCheck=true", cardNo);
            try (HttpResponse response = HttpUtil.createGet(url).execute()) {
                if (response.getStatus() == HttpStatus.HTTP_OK) {
                    JSONObject jsonObject;
                    try {
                        jsonObject = JSONUtil.parseObj(response.body());
                    } catch (JSONException e) {
                        throw new BankCardInfoException("获取alipay接口信息出错了,返回json格式不正确");
                    }
                    Boolean validated = jsonObject.getBool("validated");
                    if (validated) {
                        bankCode = jsonObject.getStr("bank");
                        cardType = jsonObject.getStr("cardType");
                        bankName = (String) invokeFunction("getBankNameByBankCode", bankCode);
                        cardTypeName = (String) invokeFunction("getCardTypeName", cardType);
                        return new BankCardInfo().setBankName(bankName)
                                .setCardType(cardType)
                                .setBankCode(bankCode)
                                .setCardTypeName(cardTypeName);
                    } else {
                        throw new BankCardInfoException("该银行卡不存在");
                    }
                } else {
                    throw new BankCardInfoException("获取alipay接口信息出错了");
                }
            }
        } else {
            bankName = (String) result.get("bankName");
            bankCode = (String) result.get("bankCode");
            cardType = (String) result.get("cardType");
            cardTypeName = (String) result.get("cardTypeName");
        }
        return new BankCardInfo().setBankName(bankName)
                .setCardType(cardType)
                .setBankCode(bankCode)
                .setCardTypeName(cardTypeName);
    }

    private static Object invokeFunction(String name, Object... args) throws BankCardInfoException {
        try {
            return javaScriptEngine.invokeFunction(name, args);
        } catch (ScriptException | NoSuchMethodException e) {
            log.error(e.getMessage(), e);
            throw new BankCardInfoException(e.getMessage());
        }
    }

}
